using System;
using System.IO;
using CodePlex.TfsLibrary.ObjectModel;
using Xunit;

namespace CodePlex.TfsLibrary.ClientEngine
{
    public class TfsEngineValidateDirectoryStructureTest
    {
        [Fact]
        public void AcceptanceTest()
        {
            try
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.EnsurePath(@"C:\Foo\Baz");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar\Biff");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bizz", @"C:\Foo\Baz", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl2", "$/Foo/Bar/Biff", @"C:\Foo\Bar\Biff", 1, 1, SourceItemStatus.Unmodified);

                engine.ValidateDirectoryStructure(@"C:\Foo");

                throw new InvalidOperationException("Should have thrown InvalidTfsDirectoryStructureException");
            }
            catch (InvalidTfsDirectoryStructureException e)
            {
                Assert.Equal(2, e.Errors.Count);

                Assert.Equal(@"C:\Foo\Bar\Biff", e.Errors[0].LocalPath);
                Assert.Equal(@"http://tfsUrl", e.Errors[0].ExpectedServerUrl);
                Assert.Equal(@"http://tfsUrl2", e.Errors[0].ActualServerUrl);
                Assert.Equal(@"$/Foo/Bar/Biff/", e.Errors[0].ExpectedServerPath);
                Assert.Equal(@"$/Foo/Bar/Biff/", e.Errors[0].ActualServerPath);

                Assert.Equal(@"C:\Foo\Baz", e.Errors[1].LocalPath);
                Assert.Equal(@"http://tfsUrl", e.Errors[1].ExpectedServerUrl);
                Assert.Equal(@"http://tfsUrl", e.Errors[1].ActualServerUrl);
                Assert.Equal(@"$/Foo/Baz/", e.Errors[1].ExpectedServerPath);
                Assert.Equal(@"$/Foo/Bizz/", e.Errors[1].ActualServerPath);
            }
        }

        [Fact]
        public void ApparentlyMovedDirectory()
        {
            try
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Biff");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Biff", 1, 1, SourceItemStatus.Unmodified);

                engine.ValidateDirectoryStructure(@"C:\Foo");

                throw new InvalidOperationException("Should have thrown InvalidTfsDirectoryStructureException");
            }
            catch (InvalidTfsDirectoryStructureException e)
            {
                Assert.Equal(1, e.Errors.Count);
                Assert.Equal(@"C:\Foo\Biff", e.Errors[0].LocalPath);
                Assert.Equal(@"http://tfsUrl", e.Errors[0].ExpectedServerUrl);
                Assert.Equal(@"http://tfsUrl", e.Errors[0].ActualServerUrl);
                Assert.Equal(@"$/Foo/Biff/", e.Errors[0].ExpectedServerPath);
                Assert.Equal(@"$/Foo/Bar/", e.Errors[0].ActualServerPath);
            }
        }

        [Fact]
        public void DirectoryNotFound()
        {
            TestableTfsEngine engine = TestableTfsEngine.Create();

            Assert.Throws<DirectoryNotFoundException>(delegate
                                                      {
                                                          engine.ValidateDirectoryStructure(@"C:\Foo");
                                                      });
        }

        [Fact]
        public void DuplicatedDirectory()
        {
            try
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo\Bar", 1, 1, SourceItemStatus.Unmodified);

                engine.ValidateDirectoryStructure(@"C:\Foo");

                throw new InvalidOperationException("Should have thrown InvalidTfsDirectoryStructureException");
            }
            catch (InvalidTfsDirectoryStructureException e)
            {
                Assert.Equal(1, e.Errors.Count);
                Assert.Equal(@"C:\Foo\Bar", e.Errors[0].LocalPath);
                Assert.Equal(@"http://tfsUrl", e.Errors[0].ExpectedServerUrl);
                Assert.Equal(@"http://tfsUrl", e.Errors[0].ActualServerUrl);
                Assert.Equal(@"$/Foo/Bar/", e.Errors[0].ExpectedServerPath);
                Assert.Equal(@"$/Foo/", e.Errors[0].ActualServerPath);
            }
        }

        [Fact]
        public void NormalScenario()
        {
            TestableTfsEngine engine = TestableTfsEngine.Create();
            engine.FileSystem.EnsurePath(@"C:\Foo");
            engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
            engine.FileSystem.EnsurePath(@"C:\Foo\Baz");
            engine.FileSystem.EnsurePath(@"C:\Foo\Baz\Biff");
            engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
            engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 1, 1, SourceItemStatus.Unmodified);
            engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Baz", @"C:\Foo\Baz", 1, 1, SourceItemStatus.Unmodified);
            engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Baz/Biff", @"C:\Foo\Baz\Biff", 1, 1, SourceItemStatus.Unmodified);

            engine.ValidateDirectoryStructure(@"C:\Foo");

            // The method's purpose is to throw an exception when things are out of whack, so
            // the happy case is no data, no exception (so no asserts).
        }

        [Fact]
        public void NotAWorkingFolder()
        {
            try
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");

                engine.ValidateDirectoryStructure(@"C:\Foo");

                throw new InvalidOperationException("Should have thrown TfsStateException");
            }
            catch (TfsStateException e)
            {
                Assert.Equal(TfsStateError.NotAWorkingFolder, e.Error);
                Assert.Equal(@"C:\Foo", e.LocalPath);
            }
        }

        [Fact]
        public void RightPathOnWrongServer()
        {
            try
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl2", "$/Foo/Bar", @"C:\Foo\Bar", 1, 1, SourceItemStatus.Unmodified);

                engine.ValidateDirectoryStructure(@"C:\Foo");

                throw new InvalidOperationException("Should have thrown InvalidTfsDirectoryStructureException");
            }
            catch (InvalidTfsDirectoryStructureException e)
            {
                Assert.Equal(1, e.Errors.Count);
                Assert.Equal(@"C:\Foo\Bar", e.Errors[0].LocalPath);
                Assert.Equal(@"http://tfsUrl", e.Errors[0].ExpectedServerUrl);
                Assert.Equal(@"http://tfsUrl2", e.Errors[0].ActualServerUrl);
                Assert.Equal(@"$/Foo/Bar/", e.Errors[0].ExpectedServerPath);
                Assert.Equal(@"$/Foo/Bar/", e.Errors[0].ActualServerPath);
            }
        }
    }
}